package com.rongji.dfish.demo.editor.view;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
import com.rongji.dfish.base.Utils;
import com.rongji.dfish.base.util.DateUtil;
import com.rongji.dfish.demo.constant.DemoConstants;
import com.rongji.dfish.demo.editor.service.EditorService;
import com.rongji.dfish.demo.editor.service.uiadaptor.AdaptorManager;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentData;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentInfo;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentRelation;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentTypeAdaptor;
import com.rongji.dfish.demo.editor.service.uiadaptor.JsonHighlighter;
import com.rongji.dfish.demo.editor.service.uiadaptor.PropertyDefine;
import com.rongji.dfish.demo.editor.service.uiadaptor.TypeAdaptor;
import com.rongji.dfish.demo.entity.DfishView;
import com.rongji.dfish.demo.entity.DfishViewDir;
import com.rongji.dfish.demo.entity.DfishViewNode;
import com.rongji.dfish.demo.pub.view.PubView;
import com.rongji.dfish.framework.FrameworkHelper;
import com.rongji.dfish.framework.plugin.file.ui.DefaultUploadFile;
import com.rongji.dfish.ui.AbstractWidget;
import com.rongji.dfish.ui.Widget;
import com.rongji.dfish.ui.command.AjaxCommand;
import com.rongji.dfish.ui.command.DialogCommand;
import com.rongji.dfish.ui.command.JSCommand;
import com.rongji.dfish.ui.command.MenuCommand;
import com.rongji.dfish.ui.command.SubmitCommand;
import com.rongji.dfish.ui.form.AbstractFormElement;
import com.rongji.dfish.ui.form.Onlinebox;
import com.rongji.dfish.ui.form.Spinner;
import com.rongji.dfish.ui.form.Text;
import com.rongji.dfish.ui.form.Textarea;
import com.rongji.dfish.ui.helper.FormPanel;
import com.rongji.dfish.ui.helper.GridPanel;
import com.rongji.dfish.ui.helper.Label;
import com.rongji.dfish.ui.helper.TabPanel;
import com.rongji.dfish.ui.json.J;
import com.rongji.dfish.ui.layout.AlbumLayout;
import com.rongji.dfish.ui.layout.ButtonBar;
import com.rongji.dfish.ui.layout.GridLayout;
import com.rongji.dfish.ui.layout.HorizontalLayout;
import com.rongji.dfish.ui.layout.VerticalLayout;
import com.rongji.dfish.ui.layout.View;
import com.rongji.dfish.ui.layout.grid.GridColumn;
import com.rongji.dfish.ui.layout.grid.Tr;
import com.rongji.dfish.ui.widget.Button;
import com.rongji.dfish.ui.widget.Html;
import com.rongji.dfish.ui.widget.Leaf;
import com.rongji.dfish.ui.widget.Split;
import com.rongji.dfish.ui.widget.SubmitButton;
import com.rongji.dfish.ui.widget.Toggle;
import com.rongji.dfish.ui.widget.TreePanel;

public class EditorView extends EditorCommonView {
	
	private static final String STR_TAB = "&nbsp;&nbsp;&nbsp;&nbsp;";
	
	public static View buildIndexView(DfishView targetView, DfishViewDir targetDir, List<DfishViewNode> viewNodes, List<DfishView> versions, String fromModule) throws Exception {
		String viewId = targetView.getViewId();
		View view = new View();
		VerticalLayout mainLayout = buildMainLayout();
		view.setNode(mainLayout);
//		view.setId(mainLayout.getId());
//		// 改变编号,以便刷新
//		mainLayout.setId(mainLayout.getId() + "_root");
		
		// FIXME 没有全选那一栏,目前没有视图切换,高度设为50
		view.findNodeById(PubView.MAIN_TOP).removeCls("bd-title").setHmin(0).setHeight(50);
		view.findNodeById(MAIN_STATUS).setHeight(0);
		view.findNodeById(MAIN_TOOL).setHeight(0);
		
//		String titleHtml="<span style='font-size:16px'>"+targetView.getViewName()+"</span>";
		String titleHtml="";
		if(EditorService.STATUS_VERSION.equals(targetView.getViewStatus())){
		    titleHtml+="<span style='font-size:14px;color:#393'>&nbsp;(保存的版本,第"+targetView.getViewVersion()+"版)</span>";
		}
//		top.add(new Html(null,titleHtml).setValign(Html.VALIGN_MIDDLE));
//		Html mainTitle = (Html) view.findNodeById(PubView.MAIN_TITLE);
//		mainTitle.setText(currView.getViewName());
		ButtonBar mainTitle = (ButtonBar) view.findNodeById(PubView.MAIN_TITLE);
		
		List<PathItem> pathItems = getDirItems(targetDir);
		pathItems.add(parsePathItem(targetView));
		fillPathBar(mainTitle, pathItems);
		
		VerticalLayout sHtml=(VerticalLayout)view.findNodeById(PubView.MAIN_VERSIONTITLE_SHELL);
		sHtml.add(new Html(null,titleHtml).setValign(Html.VALIGN_MIDDLE));
		
		ButtonBar mOper = (ButtonBar) view.findNodeById(PubView.MAIN_OPER);
		
		mOper.setPub(new Button(null).setCls("btn"));
		
		
		if (EditorService.STATUS_VERSION.equals(targetView.getViewStatus())) {
			mOper.add(new Button("恢复").setCls("btn btn-main")
					.setOn(Button.EVENT_CLICK, "this.cmd({type:'confirm',text:'确认恢复此版本吗?',yes: {type:'ajax',src:'editor/recoveryVersion?viewId="+ viewId+ "'}});"));
	    }else{
	    	mOper.add(new SubmitButton("保存").setOn(Button.EVENT_CLICK, "this.cmd({type:'dialog', title:'版本保存',template:'std', width:"+DialogCommand.WIDTH_MEDIUM+", height:"+DialogCommand.HEIGHT_MEDIUM+", src:'editor/prepareSaveVersion/" + viewId + "'});"));
	    }
		
//		Button btnEditor = new Button("编辑").setOn(Button.EVENT_CLICK, "demo.edit(this, '"+viewId+"','1','"+targetView.getViewDir()+"',  '" +targetView.getCategory() + "');");
//		mOper.add(btnEditor);

//		Button btnDel = new Button("", "删除", "VM(this).cmd({type:'confirm',text:'你确定要删除该记录吗？',yes:{type:'ajax', src:'editorDir/delete?id=" + viewId + "&type=1&pDir=" + currView.getViewDir() + "&category=" + currView.getCategory() + "'}});")
//		.setDisabled(noPermission);
//		mOper.add(btnDel);
		
		Button btnMore = new Button("更多");
		mOper.add(btnMore);
		
		btnMore.add(new Button("导出").setOn(Button.EVENT_CLICK, "$.download('editor/exportView?viewId=" + viewId + "');"));
		
		if (EditorService.STATUS_EDIT.equals(targetView.getViewStatus())){
			btnMore.add(new Button("导入").setOn(Button.EVENT_CLICK, "this.cmd({type:'ajax',src:'editor/toImport?viewId=" + viewId + "'});").setDisabled(true));
	    }
//	    btnOpera.add(new Button("复制").setOn(Button.EVENT_CLICK, "VM(this).cmd({type:'dialog',title:'复制到', template:'std', width:620, height:460, src:'editorDir/similarCreate/" + viewId + ";toCate=0'});"));
//	    btnOpera.add(new Button("", "应用于模板", "VM(this).cmd({type:'dialog',title:'应用于模块', template:'std', width:620, height:460, src:'editorDir/similarCreate/" + viewId + ";toCate=1'});"));
		
//		Button btnMove = new Button("移动");
//		btnMore.add(btnMove);
////		btnMove.add(new Button("", "移动到..", "VM(this).cmd({type:'dialog', title:'移动到...',template:'std', width:620, height:460, src:'editorDir/moveTo?id=" + viewId + "&type=1&pDir=" +currView.getViewDir() + "&category=" + currView.getCategory() + "'});"));
//		btnMove.add(new Button("", "置顶"));
//		// "VM(this).cmd({type:'ajax', src:'editorDir/move?id=" + viewId + "&type=1&pDir=" + currView.getViewDir() + "&moveType=top&category=" + currView.getCategory() + "'});"
//		btnMove.add(new Button("", "上移"));
//		// "VM(this).cmd({type:'ajax', src:'editorDir/move?id=" + viewId + "&type=1&pDir=" + currView.getViewDir() + "&moveType=up&category=" + currView.getCategory() + "'});"
//		btnMove.add(new Button("", "下移"));
//		// "VM(this).cmd({type:'ajax', src:'editorDir/move?id=" + viewId + "&type=1&pDir=" + currView.getViewDir() + "&moveType=down&category=" + currView.getCategory() + "'});"
//		btnMove.add(new Button("", "置底"));
//		// "VM(this).cmd({type:'ajax', src:'editorDir/move?id=" + viewId + "&type=1&pDir=" + currView.getViewDir() + "&moveType=bottom&category=" + currView.getCategory() + "'});"

		TabPanel contentShell = new TabPanel(MAIN_CONTENT_SHELL);
		view.replaceNodeById(contentShell);
		contentShell.getTabBar().setHeight("40").setCls("x-tabbar ");
		contentShell.getTabBar().getPub().setCls("x-tab");
		
		Widget<?> perview=getUIPreviewPanel(viewNodes,viewId, fromModule); 
		Widget<?> uiedit=getUIEditPanel(viewNodes, viewId, fromModule); 
		Widget<?> javasrc=getJavaSourcePanel(viewNodes, fromModule); 
		Widget<?> jsonsrc=getJsonSourcePanel(viewNodes, fromModule);
		Widget<?> version=getVersionPanel(versions,false,viewNodes, viewId,targetView, fromModule);
		
		contentShell.add(perview, new Button("界面预览"));
		contentShell.add(uiedit, new Button("界面编辑"));
		contentShell.add(javasrc, new Button("JAVA代码"));
		contentShell.add(jsonsrc, new Button("JSON代码"));
		contentShell.add(version, new Button("版本显示"));
		
//		contentShell.add(version, new Button("版本显示"));
		
//		ButtonBar tabHead = new ButtonBar("main_bar");
//		mDisplay.add(tabHead, "40");
//		tabHead.setCls("x-tabbar f-14").setFocusable(true);
//		tabHead.setPub(new Button(null).setCls("x-tab"));
//		//添加按钮
//		tabHead.add(new Button("界面预览").setTarget(perview.getId()).setFocus(true));
//		tabHead.add(new Button("界面编辑").setTarget(uiedit.getId()));
//		tabHead.add(new Button("JAVA代码").setTarget(javasrc.getId()));
//		tabHead.add(new Button("JSON代码").setTarget(jsonsrc.getId()));
//		tabHead.add(new Button("版本显示").setTarget(version.getId()));
//		
//		HorizontalLayout shell3=new HorizontalLayout(null);
//		mDisplay.add(shell3);
//		
//		FrameLayout film =new FrameLayout("main_film");
//		shell3.add(film);
//		film.setDft(perview.getId());
//		film.add(perview);
//		film.add(uiedit);
//		film.add(javasrc);
//		film.add(jsonsrc);
//		film.add(version);
		
		view.addCommand("copyNode", PubView.getAjaxCommand("editor/copyNode?nodeId=$0&copyType=$1"));
		view.addCommand("pasteNode", PubView.getAjaxCommand("editor/pasteNode?targetNode=$0"));
		view.addCommand("showVersions", new AjaxCommand("editor/showVersions/$0"));
		view.addCommand("saveVersion", new AjaxCommand("editor/saveVersion/$0"));
		view.addCommand("moveNode", new AjaxCommand("editor/moveNode/?nodeId=$0&moveType=$1"));
		view.addCommand("moveTargetSel", new AjaxCommand("editor/moveTargetSel/$0"));
		return view;	
	}
	
	private static Widget<?> getVersionPanel(List<DfishView> views, boolean noPermission,List<DfishViewNode> viewNodes,String viewId,DfishView currView, String fromModule) {
//		boolean isExpMod = DemoConstants.MOD_EXPERIENCE.equals(fromModule);
		
		
		GridPanel grid = new GridPanel("versions");
		grid.setFace(GridPanel.FACE_DOT).setScroll(true);
		//FIXME 应该显示当前focus哪个视图
		//FIXME nopermission 有误，在查看的时候会触发nopermission 如果控制的话，应该控制成只能恢复当前再查看的那个版本，更为合适。
//		GridColumn checkboxColumn=GridColumn.checkbox("vId", "40");
//		grid.addColumn(0,checkboxColumn);
//		checkboxColumn.setAlign(GridColumn.ALIGN_CENTER);
		
		grid.addColumn(GridColumn.text("viewVersion", "ver", "版本", "60").setAlign(GridColumn.ALIGN_RIGHT));
		grid.addColumn(GridColumn.text("updateTime", "time", "更新时间", "140").setDataFormat("yyyy-MM-dd HH:mm:ss").setAlign(GridColumn.ALIGN_CENTER));
//		grid.addColumn(GridColumn.text("viewCreator", "creator", "创建人", "100"));
		grid.addColumn(GridColumn.text("viewRemark", "remark", "备注", "*"));   
//		grid.addColumn(GridColumn.text("viewId", "vId", "操作", "100").setFormat("[<a href='javascript:' onclick=\"if(confirm('你确定要恢复版本吗？')){VM(this).cmd({type:'ajax',src:'editor/recoveryVersion?viewId='+'$vId'});}\">恢复</a>]$nbsp" +
//				" [<a href='javascript:' onclick=\"editor.dir.enterEditor(this,'$vId');\">查看</a>]"));
		grid.addColumn(GridColumn.text("viewId", "vId", "操作", "100").setFormat("javascript:return editor.file.versionFormat($vId,'" + viewId + "',this);"));
		grid.addColumn(GridColumn.hidden("viewId", "vId"));
		grid.setGridData(views);
        
		HorizontalLayout root = new HorizontalLayout("version");
        Html html =getVersionMessagePanel(currView,noPermission);
        VerticalLayout vert=new VerticalLayout("");
        root.add(vert);
		vert.add(grid);
		
//		if (isExpMod) {
//			ButtonBar bb=new ButtonBar("f_btn").setCls("groupbar").setAlign(ButtonBar.ALIGN_LEFT).setSpace(1);
//			bb.setPub(new Button(null).setCls("btn"));
//			bb.add(new Button("批量删除").setOn(Button.EVENT_CLICK, "demo.delVersionBatch(this);"));
//			vert.add(bb,"35");
//		}
//        root.add(grid);
        root.add(html,"240");
        return root;
	}
	
	/**
	 * 点击查看
	 * 右侧显示相应的版本信息
	 * @param currView
	 * @param noPermission
	 * @return
	 */
	private static Html getVersionMessagePanel( DfishView currView,
			boolean noPermission) {
		
		String viewName = currView.getViewName();
		String viewCreator = currView.getViewCreator();
		String viewRemark = currView.getViewRemark();
		Long viewOrder = currView.getViewOrder();
		Date createTime = currView.getCreateTime();
		Date updateTime = currView.getUpdateTime();


		Html html=new Html("","<div id='folderinfo'>" +
		"名称："+viewName+"<br/>" +
		"类型："+"视图文件"+"<br/>" +
//		"创建人:"+viewCreator+"<br/>"+
		"备注："+viewRemark+"<br/>" +
		"排序："+viewOrder+"<br/>" +
		"创建时间："+DateUtil.format(createTime,DateUtil.PATTERN_FULL) + "<br/>" +
		"更新时间："+DateUtil.format(updateTime,DateUtil.PATTERN_FULL) + "<br/>" +
		"属性："+(noPermission?"只读":"可编辑")+"<br/>" +"</div>");
		html.setScroll(true).setCls("bd-title bd-onlyleft").setWmin(1);
		return html;

	}


	private static VerticalLayout buildMainPanel(List<DfishViewNode> viewNodes, String viewId) {
//		main.setStyle("border:1px solid #999");
//		main.setHmin(2);
//		main.setWmin(2);
//		main.setTabHeight("36");
//		main.setHeight("*");//FIXME 理论上horizontal必须自动补高度，否则会变成自适应高度。
//		main.setTabPosition(TabPanel.POS_BOTTOM_LEFT);
//		
//		main.addSubWidget(null, "界面预览", getUIPreviewPanel(viewNodes));
//		main.addSubWidget(null, "界面编辑", getUIEditPanel(viewNodes, viewId));
//		main.addSubWidget(null, "JAVA代码", getJavaSourcePanel(viewNodes));
//		main.addSubWidget(null, "JSON代码", getJsonSourcePanel(viewNodes));
		VerticalLayout main=new VerticalLayout("main");
		
		return main;
	}


	private static Widget<?> getUIPreviewPanel(List<DfishViewNode> viewNodes,String viewId, String fromModule) {
		HorizontalLayout root = new HorizontalLayout("preview");
		try {
	        Widget<?> preview = AdaptorManager.getInstance().getViewBuilder().getWidget(viewNodes,true);
	        if (preview == null) {
	        	preview = new Html("");
	        }
	        preview.setStyle("margin:6px 6px 0px 6px;");
	        // FIXME 套壳需要优化
	        root.add(new VerticalLayout(null).add(preview, "*"));
        } catch (Exception e) {
        	root.add(getFailoverPanel(null,e));
        }
		TreePanel tree=buildComponentInfoPanel(viewNodes,viewId);//全局定义    保留界面浏览 去除其他三个
		root.add(tree,"240");
		return root;
	}
	
	private static Widget<?> getFailoverPanel(String id,Exception e) {
		StringBuilder html = new StringBuilder();
		html.append("出错啦╥﹏╥...<br/>");
		StringWriter writer = new StringWriter();
		e.printStackTrace(new PrintWriter(writer));
		html.append("<pre>"+writer.toString()+"</pre>");
		FrameworkHelper.LOG.debug(null,e);
//		StackTraceElement[] errors = e.getStackTrace();
//		html.append(e.getClass().getName() + ":&nbsp;&nbsp;" + e.getMessage() + "<br/>");
//		if (errors != null) {
//			for (StackTraceElement st : errors) {
//				html.append("&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;&nbsp;").append(st.getClassName()).append(".").append(st.getMethodName())
//					.append("(").append(st.getFileName()).append(":").append(st.getLineNumber()).append(")").append("<br/>");
//			}
//		}
		return new Html(id,html.toString()).setScroll(true);
	}
	
	private static Widget<?> getUIEditPanel(List<DfishViewNode> viewNodes, String viewId, String fromModule) {
		try {
			boolean isExpMod = DemoConstants.MOD_EXPERIENCE.equals(fromModule);
			
			VerticalLayout vert = new VerticalLayout("vert").setStyle("margin:5px").setHmin(10).setWmin(10);
			
			ComponentData data = getComponentData(viewNodes);
			
			StringBuilder editContent = new StringBuilder();
			if (data != null) {
				String json = new Gson().toJson(data);
				editContent.append(J.formatJson(json));
			}
			
//		editContent.append("||敬请期待...");
//		vert.addNode(new Html(getPrettyHtml(editContent.toString())).setStyle("line-height:100%;").setScroll(true), "*");
			
			Textarea textArea = new Textarea("editContent", "编辑内容", editContent.toString())
			.setHideLabel(true)
			.setHeight("*").setReadonly(!isExpMod);
			vert.add(textArea, "*");
			
			if (isExpMod) {
				ButtonBar btnBar = new ButtonBar("btnBar");
				vert.add(btnBar, "50");
				btnBar.setStyle("padding-left:8px;");
				btnBar.add(new Button("", "确定", "this.cmd({type:'submit',src:'editor/rebuildView/" + viewId + "'});").setCls("btn"));
			}
			
			return vert;
        } catch (Exception e) {
        	return getFailoverPanel("vert",e);
        }
	}
	
	public static ComponentData getComponentData(List<DfishViewNode> viewNodes) {
		// FIXME 理论上有可能产生的有可能是多根节点
		ComponentData rootData = null;
		if (viewNodes != null) {
			Map<String, List<DfishViewNode>> nodeMap = new HashMap<String, List<DfishViewNode>>();
			// 父节点编号对应子节点集合
			for (DfishViewNode node : viewNodes) {
				List<DfishViewNode> list = nodeMap.get(node.getNodeParent());
				if (list == null) {
					list = new ArrayList<DfishViewNode>();
					nodeMap.put(node.getNodeParent(), list);
				}
				list.add(node);
			}
			List<DfishViewNode> rootNodes = nodeMap.remove(DemoConstants.ID_ROOT);
			// FIXME 理论上根节点应该只有一个
			if (Utils.notEmpty(rootNodes)) {
				DfishViewNode rootNode = rootNodes.get(0);
				rootData = AdaptorManager.parseData(rootNode);
				fillComponentData(rootData, rootNode.getNodeId(), nodeMap);
			}
		}
		return rootData;
	}
	

	
	private static void fillComponentData(ComponentData parent, String pId, Map<String, List<DfishViewNode>> nodeMap) {
		List<DfishViewNode> list = nodeMap.get(pId);
		if (list != null) {
			for (DfishViewNode viewNode : list) {
				ComponentData node = AdaptorManager.parseData(viewNode);
//				if("Checkboxgroup".equals(parent.getType())){
//					if(parent.getTargets()==null){
//						parent.setTargets(new ArrayList<ComponentData>());
//					}
//					parent.getTargets().add(node);
//				}else{
					if(parent.getNodes()==null){
						parent.setNodes(new ArrayList<ComponentData>());
					}
					parent.getNodes().add(node);
//				}
				fillComponentData(node, viewNode.getNodeId(), nodeMap);
			}
		}
	}
	
	private static Widget<?> getJavaSourcePanel(List<DfishViewNode> viewNodes, String fromModule) {
		try {
			String code = AdaptorManager.getInstance().getJavaCodeBuilder().getJavaCode(viewNodes);
			return new Html("javaSrc",getJavacodePrettyHtml(code)).setScroll(true);
        } catch (Exception e) {
        	return getFailoverPanel("javaSrc",e);
        }
	}
	
	private static Widget<?> getJsonSourcePanel(List<DfishViewNode> viewNodes, String fromModule)  {
		try {
			Widget<?> preview = AdaptorManager.getInstance().getViewBuilder().getWidget(viewNodes,false);
			return new Html("jsonSrc",JsonHighlighter.highlight(preview==null?null:preview.asJson())).setScroll(true);
        } catch (Exception e) {
        	return getFailoverPanel("jsonSrc",e);
        }
	}
	


//	private static class VisitResult{
//		int end;
//		boolean hasSubNode;
//	}

	private static String getJavacodePrettyHtml(String code) {
		if (code == null) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		final int STATE_IN_DOUBLE_QUOTA=1;
		final int STATE_IN_SINGLE_QUOTA=2;
		final int STATE_NO_QUOTA=0;
		int state=STATE_NO_QUOTA;
		sb.append("<div id='codePreview'>");
		char[] ca = code.toCharArray();
		for (int i = 0; i < ca.length; i++) {
			switch (ca[i]) {
			case '&':
				sb.append("&amp;");
				break;
			case '<':
				sb.append("&lt;");
				break;
			case '>':
				sb.append("&gt;");
				break;
			case '\"':
				if((i>0&&ca[i-1]=='\\' )|| state==STATE_IN_SINGLE_QUOTA){
					sb.append('"');
				}else if(state==STATE_NO_QUOTA){
					sb.append("<i class='q'>\"");
					state=STATE_IN_DOUBLE_QUOTA;
				}else{
					sb.append("\"</i>");
					state=STATE_NO_QUOTA;
				}
				break;
			case '\'':
				if((i>0&&ca[i-1]=='\\' )|| state==STATE_IN_DOUBLE_QUOTA){
					sb.append('\'');
				}else if(state==STATE_NO_QUOTA){
					sb.append("<i class='q'>'");
					state=STATE_IN_SINGLE_QUOTA;
				}else{
					sb.append("'</i>");
					state=STATE_NO_QUOTA;
				}
				break;
			case '\r':
				sb.append("<br/>");
				if(i+1<ca.length&&ca[i+1]=='\n'){
					i++;
				}
				break;
			case '\n':
				sb.append("<br/>");
				break;
			case '\t':
				sb.append(STR_TAB);
				break;
			default:
				if (ca[i] < 32 || (ca[i] > 127 && ca[i] < 256)) {
					//控制字符不输出，
				} else {
					if(state==STATE_NO_QUOTA&&((ca[i]>='a'&&ca[i]<='z')||(ca[i]>='A'&&ca[i]<='Z')||ca[i]=='_')) {
						for (int j=i+1;j<ca.length;j++){//找到个关键字
							if(ca[j]<'0'||(ca[j]>'9'&&ca[j]<'A')||(ca[j]>'Z'&&ca[j]<'_')||ca[j]==96||ca[j]>'z'){
								if (KEYWORDS.contains(new String(ca,i,j-i))){
									sb.append("<span class='k'>").append(ca,i,j-i).append("</span>");
								} else {
									sb.append(ca,i,j-i);
								}
								i=j-1;
								break;
							}
						}
					}else{
						sb.append(ca[i]);		
					}
				}
			}
		}

		sb.append("</div>");
		return sb.toString();
	}
	private static final HashSet<String> KEYWORDS =new HashSet<String>(Arrays.asList(
			"package","import","class",
			"extends","interface","implemnets",
			"int","char","double","float","byte","short","boolean",
			"public","private","protected",
			"static","final","const","this","super",
			"false","true","null",
			"if","else","do","while","switch","case","for",
			"break","return","continue",
			"default","new","try","catch","finally","synchronized","throw","throws",
			"transient","volatile","strictfp","instanceof","native",
			"goto","enum","assert",
			"var"));
	
	
	/**
	 * 视图右侧组件展开模块
	 * @param viewNodes
	 * @param viewId
	 * @return
	 */
	private static TreePanel buildComponentInfoPanel(
			List<DfishViewNode> viewNodes,String viewId) {
		
		TreePanel tree=new TreePanel("compTree");
		tree.setScroll(true).setCls("bd-title bd-onlyleft").setWmin(1).setEscape(true);

		Leaf compRoot=new Leaf();
		tree.add(compRoot.setId(DemoConstants.ID_ROOT).setText("组件信息"));
		//FIXME tree.addNode
		String contextmenu = "editor.file.nodeMenu(this, this.x.id, '" + viewId + "');";
		String clickCmd = "editor.file.highlight(this,'" + viewId + "');";
		tree.setPub(new Leaf().setOn("click", clickCmd).setOn(Leaf.EVENT_CONTEXTMENU, contextmenu));
		tree.setOn(AlbumLayout.EVENT_CONTEXTMENU,contextmenu);
//		tree.setOn(AlbumLayout.EVENT_CONTEXTMENU, "editor.file.contextmenu(this);");
		
		HashSet<String> allId=new HashSet<String>();
		HashMap<String,List<DfishViewNode>> allSubs=new HashMap<String,List<DfishViewNode>>();
		for(DfishViewNode node:viewNodes){
			allId.add(node.getNodeId());
			//获取父类编码的视图节点集合
			List<DfishViewNode> subs=allSubs.get(node.getNodeParent());
			if(subs==null){
				subs =new ArrayList<DfishViewNode>(); 
				allSubs.put(node.getNodeParent(),subs);
			}
			subs.add(node);
		}
		for(DfishViewNode node:viewNodes){
			//非视图子节点
			if(allId.contains(node.getNodeParent())){
				continue;
			}
			fillCompTreeItem(compRoot,node,allSubs);
		}
		return tree;
	}
	

	private static void fillCompTreeItem(Leaf shell, DfishViewNode node,
			HashMap<String, List<DfishViewNode>> allSubs) {
		if(node==null){return;}
		shell.setOpen(true);
		//去父类中进行构建展开节点
		if(Utils.isEmpty(node.getNodeParent())||node.getNodeParent().equals(DemoConstants.ID_ROOT)){
			shell.setSrc("editor/open/ROOT"+node.getViewId());
		}else{
			shell.setSrc("editor/open/"+node.getNodeParent());
		}
		
		Leaf t=new Leaf().setId(node.getNodeId());
		shell.add(t);
		if(Utils.notEmpty(node.getNodeName())){
			if(node.getNodeName().length()<10){
				t.setText(node.getNodeType()+"("+node.getNodeName()+")");
			} else {
				t.setText(node.getNodeType()+"("+node.getNodeName().substring(0, 8)+"...)");
			}
			
		}else{
			t.setText(node.getNodeType());
		}
		List<DfishViewNode> subs=allSubs.get(node.getNodeId());
		if(subs!=null){
			//循环到无父类节点
			for(DfishViewNode sub:subs){
				fillCompTreeItem(t,sub,allSubs);
			}
		}
	}

	public static View buildPropView(DfishViewNode viewNode, DfishViewNode pNode,boolean readonly) {
		View view = PubView.buildDialogView();
		
		TypeAdaptor adaptor = AdaptorManager.getInstance().getAdaptor(viewNode.getNodeType());
		// FIXME 
		VerticalLayout main = new VerticalLayout(PubView.DIALOG_MAIN).setScroll(true);
		view.replaceNodeById(main);
		
		FormPanel propForm = new FormPanel(null);
		main.add(propForm, "-1");
		// FIXME addHidden放在
		propForm.addHidden("nodeId", viewNode.getNodeId());
		propForm.addHidden("viewId", viewNode.getViewId());
		propForm.addHidden("nodeType", viewNode.getNodeType());
		propForm.addHidden("nodeParent", pNode.getNodeId());
		propForm.addHidden("parentType", pNode.getNodeType());
		
//		form.add(new Text("nodeId","节点编号",viewNode.getNodeId()));
//		form.add(new Text("nodeType","节点类型",viewNode.getNodeType()));
		Boolean readonlyShow=readonly?true:null;
		ComponentData data = AdaptorManager.parseData(viewNode);
		propForm.addHidden("nodeMode", data.getMode());
		if(adaptor==null){
			propForm.add(new Label("", "<div style='padding-left:20px'><span style='font-weight:bold;font-size:12pt;'>"+viewNode.getNodeType()+"</span> [<span style='color:gray'>查看API</span>]</div>").setEscape(false).setHideLabel(true));			
		}else{
			Class<?> clz=adaptor.getClass();
			if(adaptor instanceof ComponentTypeAdaptor){
				ComponentTypeAdaptor cast=(ComponentTypeAdaptor)adaptor;
				clz=cast.getClz();
			}
			String javaApiPath=clz.getName().replace('.', '/');
			propForm.add(new Label("", "<div style='padding-left:20px'><span style='font-weight:bold;font-size:12pt;'>"+viewNode.getNodeType()+"</span> [<a href='api/java/"+javaApiPath+".html' target='_blanck'>查看API</a>]" +
					(Utils.isEmpty(data.getMode())?"":("<span style='color:gray'>&nbsp;(作为"+Utils.escapeXMLword(data.getMode())+"添加)</span>"))+
					"</div>").setEscape(false).setHideLabel(true));
		}
		TypeAdaptor pAdaptor = AdaptorManager.getInstance().getAdaptor(pNode.getNodeType());
		if (pAdaptor != null) {
			List<PropertyDefine> appendingProps=AdaptorManager.getInstance().getCompRelation().getAppendingProperies(pNode.getNodeType(), viewNode.getNodeType(), data.getMode());
			// 补充父节点的追加属性
			if (Utils.notEmpty(appendingProps)) {
				main.add(new Toggle().setText("追加属性").setOpen(true).setHr(true),"-1");
				FormPanel formParent=new FormPanel("form_parent");
				main.add(formParent,"-1");
				Map<String, String> parentProps = data.getParentProps();
				if(parentProps==null){
					parentProps=new LinkedHashMap<String, String>();
				}
				for (PropertyDefine propDef : appendingProps) {
					AbstractWidget<?>  elem=AdaptorManager.getInstance().getViewBuilder().getFormElement(propDef, parentProps.get(propDef.getName()),pAdaptor.getTypeName());
					if(elem instanceof AbstractFormElement<?, ?>){
							((AbstractFormElement<?, ?>) elem).setReadonly(readonlyShow);
					}
					formParent.add(elem);
				}
				formParent.getPrototype().getColumns().get(0).setWidth("150");
			}
		}
		adaptor= AdaptorManager.getInstance().getCompInfo().getComponentDefine((ComponentTypeAdaptor) adaptor);
		if(adaptor!=null&&adaptor.getDefineProps()!=null&&adaptor.getDefineProps().size()>0){
			//部分组件没有属性(-_-!) 只能添加下级节点。
			main.add(new Toggle().setText("控件属性").setOpen(true).setHr(true),"-1");
			FormPanel formProp=new FormPanel("form_self");
			main.add(formProp,"-1");
			Map<String,String>props= data.getProps();
			for (PropertyDefine prop: adaptor.getDefineProps()){
				String value=null;
				if(Utils.notEmpty(props)){
					value=props.get(prop.getName());
				}
				if(Utils.isEmpty(value)){
					value=prop.getDefaultValue();
				}
				AbstractWidget<?> elem=AdaptorManager.getInstance().getViewBuilder(). getFormElement(prop, value,adaptor.getTypeName());
				if(elem instanceof AbstractFormElement<?, ?>){
					if( ((AbstractFormElement<?, ?>) elem).getReadonly()==null||!((AbstractFormElement<?, ?>) elem).getReadonly()){
						((AbstractFormElement<?, ?>) elem).setReadonly(readonlyShow);
					}
					
					if(((AbstractFormElement) elem).getName().equals("options")){
						String[] elems = {};
						if(((AbstractFormElement<?, ?>) elem).getValue()!=null){
							elems = ((String)((AbstractFormElement<?, ?>) elem).getValue()).replace("[", "").replace("]", "").replace("\"", "").split(",");
						}
						Map<String,String> datas = new LinkedHashMap<String, String>();
						for(int i=0;i<elems.length;i+=2){
							datas.put(elems[i], elems[i+1]);
						}
						VerticalLayout vl=buildExtPropTable(((AbstractFormElement<?, ?>) elem).getName(),"options","P",datas,propForm,readonly);
						main.add(vl,"-1");
						
					} else {
						formProp.add(elem);
					}

				}
			}
			formProp.getPrototype().getColumns().get(0).setWidth("150");
		}
		
		//Data属性
		if (adaptor!=null&&AdaptorManager.getInstance().getCompInfo().hasDataProp(adaptor.getTypeName())) {//FIXME 理论上应该根据组件是否DataContainer实例来确认
			main.add(new Toggle().setText("扩展属性(data)").setOpen(true).setHr(true),"-1");
			VerticalLayout vl=buildExtPropTable("扩展属性","data","D",data.getDataProps(),propForm,readonly);
			main.add(vl,"-1");
		}
		//HIDDEN属性
		if (adaptor!=null&&AdaptorManager.getInstance().getCompInfo().hasHiddensProp(adaptor.getTypeName())) {//FIXME 理论上应该根据组件是否DataContainer实例来确认
			main.add(new Toggle().setText("隐藏表单(hiddens)").setOpen(true).setHr(true),"-1");
			VerticalLayout vl=buildExtPropTable("隐藏表单","hiddens","H",data.getHiddensProps(),propForm,readonly);
			main.add(vl,"-1");
		}
		
		//Hiddens属性 —— 也可以当成子节点，但实际效果并不好
		//Evnet 属性
		//HIDDEN属性
		if (adaptor!=null&&AdaptorManager.getInstance().getCompInfo().hasEventProp(adaptor.getTypeName())) {//FIXME 理论上应该根据组件是否DataContainer实例来确认
			main.add(new Toggle().setText("事件动作(event)").setOpen(true).setHr(true),"-1");
			VerticalLayout vl=buildExtPropTable("事件动作","event","E",data.getEventProps(),propForm,readonly);
			main.add(vl,"-1");
		}
	
		ButtonBar bbp=(ButtonBar)view.findNodeById(PubView.DIALOG_BTN); 
		
		if(!readonly){
			SubmitButton submit=new SubmitButton("","确定","this.cmd('saveNode');");
			submit.setCls("btn btn-submit");
			bbp.add(0, submit);
		}
		
		view.addCommand("saveNode",new SubmitCommand( "editor/saveNode"));
		String orderStr=viewNode.getNodeOrder()==null?"":String.valueOf(viewNode.getNodeOrder());
		main.add(new Toggle().setText("控制属性").setOpen(true).setHr(true),"-1");
		FormPanel formCtrl=new FormPanel("form_ctrl");
		main.add(formCtrl,"-1");
		formCtrl.add(new Text("nodeOrder","排序号",orderStr).setReadonly(readonlyShow));
		
		return view;
	}


	private static VerticalLayout buildExtPropTable(String titleText,String id,String prefix,Map<String,String> extProps,FormPanel hiddenContainner,boolean readonly) {
		VerticalLayout vp=new VerticalLayout(null);
		vp.setCls("bd-title").setStyle("margin:0 20px").setHmin(2).setWmin(42);
		HorizontalLayout title=new HorizontalLayout(null).setCls("bd-title bd-onlybottom").setHmin(1);
		vp.add(title,"-1");
		title.add(new Html(null,"<span style='line-heght:150%;font-weight:bold'>&nbsp;"+titleText+"</span>"));
		if(readonly){
			title.add(new Html(null,"<span style='line-heght:150%;color:gray' \">新增一行</span>&nbsp;").setAlign(Html.ALIGN_RIGHT));
		}else{
			title.add(new Html(null,"<a style='line-heght:150%;' href='javascript:;' onclick=\"editor.file.addProp('"+id+"',this);\">新增一行</a>&nbsp;").setAlign(Html.ALIGN_RIGHT));
		}
		GridLayout grid=new GridLayout("ct_"+id);
		grid.setHeight("100").setScroll(true).setFace(GridLayout.FACE_CELL).setCellpadding(0);
		grid.addColumn(GridColumn.text("K", "35%"));
		grid.addColumn(GridColumn.text("V", "*"));
		grid.addColumn(GridColumn.text("O", "50"));
		vp.add(grid);
		
		if (extProps != null) {
			int index = 1;
			Boolean readonlyShow=readonly?true:null;
			for (Map.Entry<String,String> entry : extProps.entrySet()) {
				Tr tr=new Tr(id+"_row_"+index);
				grid.add(tr);
				if("E".equals(prefix)){
					tr.setData("K",new Onlinebox(prefix+"K_" + index, "",entry.getKey(), "editor/eventOptions?key=$text").setTransparent(true).setReadonly(readonlyShow));
				}else{
					tr.setData("K",new Text(prefix+"K_" + index, "",entry.getKey()).setTransparent(true).setReadonly(readonlyShow));
				}
				tr.setData("V",new Text(prefix+"V_" + index, "", entry.getValue()).setTransparent(true).setReadonly(readonlyShow));
				if(readonly){
				tr.setData("O",new Html("","&nbsp;<span style='color:gray'>删除&nbsp;</span>").setAlign(Html.ALIGN_CENTER));
				}else{
				tr.setData("O",new Html("","&nbsp;<a href='javascript:;' onclick=\"VM(this).find('"+id+"_row_"+index+"').remove()\">删除&nbsp;</a>").setAlign(Html.ALIGN_CENTER));
				}
				index++;
			}
			if (index > 1) {
				hiddenContainner.addHidden(id+"_index", String.valueOf(index - 1));
			}
		}
		return vp;
	}


	public static MenuCommand buildNodeMenu(DfishViewNode viewNode, boolean noPermission,Set<String>subViewNodeTypes,Set<String>subViewNodeIds, String fromModule) {
		ComponentInfo cinfo=AdaptorManager.getInstance().getCompInfo(); 
		ComponentRelation crel=AdaptorManager.getInstance().getCompRelation(); 
		MenuCommand menu = new MenuCommand(); 
		String type=viewNode==null?null:viewNode.getNodeType();
		//如果某个组件在父节点下是唯一的。这时候就要判断，是否它原先是否有这类属性存在。
		//这个变量用于判定原先是否已经存在这种唯一的节点了。
		//这个变量对特殊节点无效，gridLayout增加了pub还是可以增加thead和combofield
		boolean canNotNew=false;
		if(type==null&&Utils.notEmpty(subViewNodeTypes)){
			canNotNew=true;
		}
		boolean isExpMod = DemoConstants.MOD_EXPERIENCE.equals(fromModule);
		if(!canNotNew && isExpMod ){
			Button newBtn = new Button("", "新增子节点");
			menu.add(newBtn);
			List<ComponentRelation.Information> acceptTypes=crel.getAcceptType(type);
			boolean newBtnDisabled=acceptTypes==null||acceptTypes.size()==0||noPermission;
			newBtn.setDisabled(newBtnDisabled);
			fillNewButton("",viewNode, subViewNodeTypes, acceptTypes, newBtn);
			Map<String,List<ComponentRelation.Information>>otherPart=crel.getOtherType(type);
			if(Utils.notEmpty(otherPart)){
				for(Map.Entry<String,List<ComponentRelation.Information>> entry:otherPart.entrySet()){
					Button newBtnOther = new Button( "新增 "+cinfo.getCategoryName(entry.getKey())+"["+entry.getKey()+"]");
					menu.add(newBtnOther);
					newBtnOther.setDisabled(noPermission);
					fillNewButton("["+entry.getKey()+"]",viewNode, subViewNodeTypes, entry.getValue(), newBtnOther);
				}
			}
		}
//		List<String> cateKeys=new ArrayList<String>(cates.keySet());
//		cinfo.sortCategory(cateKeys);
//		//先确定当前节点已有的下级节点的type类型。看看是否触发单一检查
//		
//		for(String cate:cateKeys){
//			Button cateBtn = new Button("", cinfo.getCategoryName(cate), "");
//			newBtn.add(cateBtn);
//			for(String subAdaptor:cates.get(cate)){
//				String typeName=cinfo.getTypeName(subAdaptor);
//				boolean singleLimit=containSingle&&(crel.acceptSingle(type , subAdaptor)||((type==null||type.equals(null)&&"View".equals(subAdaptor))));
//				cateBtn.add(new Button("", typeName,
//				"VM(this).cmd({'type':'ajax','src':'editor/editNode?nodeId=NEW&nodeType="+subAdaptor+"&nodeParent="+viewNode.getNodeId()+"&parentType="+viewNode.getNodeType()+"&viewId="+viewNode.getViewId()+"'});").setDisabled(singleLimit));
//			}
//		}
//		boolean newBtnDisabled=acceptTypes==null||acceptTypes.size()==0||noPermission;
//
//		newBtn.setDisabled(newBtnDisabled);
//		if (DemoConstants.ID_ROOT.equals(viewNode.getNodeId())) {
//			//根节点是特殊节点，它的属性不全，并且他只有增加View节点的功能，不允许做其他操作，所以直接返回
//			if(!canNotNew){
//				menu.add(new Split());
//			}
//			menu.add(new Button("查看").setDisabled(true));
//			menu.add(new Button("删除").setDisabled(true));
//			menu.add(new Split());
//			menu.add(new Button("位置").setDisabled(true));
//			return menu;
//		}
		//根节点"组织信息"右击只能新增子节点
		if(viewNode.getNodeId().equals(DemoConstants.ID_ROOT)){
			return menu;
		}
		//FIXME 特殊节点增加
		if (isExpMod) {
			Map<String,List<ComponentRelation.Information>> specialPart=crel.getSpecialParts(type);
			if(Utils.notEmpty(specialPart)){
				for(Map.Entry<String,List<ComponentRelation.Information>> entry:specialPart.entrySet()){
					//判断节点是否可以重复
					Button cateBtn = new Button("", "设置 "+cinfo.getCategoryName(entry.getKey())+"&lt;"+entry.getKey()+"&gt;").setDisabled(!isExpMod);
					menu.add(cateBtn);
					boolean singleLimit= subViewNodeIds.contains("<"+entry.getKey()+">");
					for(ComponentRelation.Information subAdaptor:entry.getValue()){
						String typeName=cinfo.getTypeName(subAdaptor.getSubType());
						cateBtn.add(new Button("", typeName,
								"VM(this).cmd({'type':'ajax','src':'editor/editNode?nodeId=NEW&nodeType="+subAdaptor.getSubType()+"&nodeParent="+viewNode.getNodeId()+"&parentType="+viewNode.getNodeType()+"&viewId="+viewNode.getViewId()+"&nodeMode=%3C"+entry.getKey()+"%3E&fromModule="+fromModule+"'});")
						.setDisabled(singleLimit&&subAdaptor.isSingle()));
					}
				}
			}
			menu.add(new Split());
			// FIXME 剪切功能先隐藏
//			menu.add(new Button("剪切").setOn(Button.EVENT_CLICK,"VM(this).cmd({'type':'ajax','src':'editor/copyNode?nodeId="+viewNode.getNodeId()+"&copyType="+DemoConstants.OPER_CUT+"'});").setDisabled(!isExpMod));
		}
			menu.add(new Button("复制").setOn(Button.EVENT_CLICK,"VM(this).cmd({'type':'ajax','src':'editor/copyNode?nodeId="+viewNode.getNodeId()+"&copyType="+DemoConstants.OPER_COPY+"'});"));
		
		if (isExpMod) {
			menu.add(new Button("粘贴").setOn(Button.EVENT_CLICK,"VM(this).cmd({'type':'ajax','src':'editor/pasteNode?targetNode="+viewNode.getNodeId()+"&viewId="+viewNode.getViewId()+"'});").setDisabled(noPermission));
			
			Button poschg=new Button("","位置","").setDisabled(noPermission&&DemoConstants.ID_ROOT.equals(viewNode.getNodeParent()));/*&&DemoConstants.ID_ROOT.equals(viewNode.getNodeParent())*/
			menu.add(poschg);
			
			poschg.add(new Button("","置顶","VM(this).cmd({'type':'ajax','src':'editor/moveNode?nodeId="+viewNode.getNodeId()+"&moveType="+DemoConstants.MOVE_TOP+"&viewId="+viewNode.getViewId()+"'});"));//FIXME add 和addNode
			poschg.add(new Button("","上移","VM(this).cmd({'type':'ajax','src':'editor/moveNode?nodeId="+viewNode.getNodeId()+"&moveType="+DemoConstants.MOVE_UP+"&viewId="+viewNode.getViewId()+"'});"));
			poschg.add(new Button("","下移","VM(this).cmd({'type':'ajax','src':'editor/moveNode?nodeId="+viewNode.getNodeId()+"&moveType="+DemoConstants.MOVE_DOWN+"&viewId="+viewNode.getViewId()+"'});"));//FIXME add 和addNode
			poschg.add(new Button("","置底","VM(this).cmd({'type':'ajax','src':'editor/moveNode?nodeId="+viewNode.getNodeId()+"&moveType="+DemoConstants.MOVE_BOTTOM+"&viewId="+viewNode.getViewId()+"'});"));
			
			menu.add(new Split());
			
			menu.add(new Button("","删除","if(confirm('确认删除节点 吗?')){ VM(this).cmd({'type':'ajax','src':'editor/deleteNode/"+viewNode.getNodeId()+"'});}").setDisabled(noPermission ));
			
		}
		//rb
//		menu.add(new Split());
//		menu.add(new Button("","复制","VM(this).cmd({'type':'ajax','src':'editor/copyNode?nodeId="+viewNode.getNodeId()+"&viewId="+viewNode.getViewId()+"'});"));
//		menu.add(new Button("","粘贴","VM(this).cmd({'type':'ajax','src':'editor/pasteNode?nodeId="+viewNode.getNodeId()+"&viewId="+viewNode.getViewId()+"'});"));
		
		menu.add(new Split());
		menu.add(new Button("", "属性","VM(this).cmd({'type':'ajax','src':'editor/editNode?nodeId="+viewNode.getNodeId()+"&fromModule=" + fromModule + "'});"));
//		poschg.add(new Button("","移动到...","VM(this).cmd({'type':'ajax','src':'editor/moveTargetSel?nodeId="+viewNode.getNodeId()+"&viewId="+viewNode.getViewId()+"'});"));
				
		return menu;
	}

	private static void fillNewButton(String nodeMode,DfishViewNode viewNode,Set<String>subViewNodeTypes,List<ComponentRelation.Information> acceptTypes,Button newBtn) {
		ComponentInfo cinfo=AdaptorManager.getInstance().getCompInfo(); 
		ComponentRelation crel=AdaptorManager.getInstance().getCompRelation(); 
		String type=viewNode==null?null:viewNode.getNodeType();
		boolean containSingle=false;
		LinkedHashMap<String,List<String>> cates=new LinkedHashMap<String,List<String>>();
		if(acceptTypes!=null){
			for(ComponentRelation.Information acceptType:acceptTypes){
				if(acceptType.isSingle()){
					if(subViewNodeTypes.contains(acceptType.getSubType())){
						containSingle=true;
					}
				}
				String cate=cinfo.getCategory(acceptType.getSubType());
				List<String> typesInCate=cates.get(cate); 
				if(typesInCate==null){
					typesInCate=new ArrayList<String>();
					cates.put(cate,typesInCate);
				}
				typesInCate.add(acceptType.getSubType());
			}
		}
		List<String> cateKeys=new ArrayList<String>(cates.keySet());
		cinfo.sortCategory(cateKeys);
		//先确定当前节点已有的下级节点的type类型。看看是否触发单一检查
		
		for(String cate:cateKeys){
			Button cateBtn = new Button("", cinfo.getCategoryName(cate), "");
			newBtn.add(cateBtn);
			for(String subAdaptor:cates.get(cate)){
				String typeName=cinfo.getTypeName(subAdaptor);
				boolean singleLimit=containSingle&&(crel.acceptSingle(type , subAdaptor)||((type==null||type.equals(null)&&"View".equals(subAdaptor))));
				cateBtn.add(new Button("", typeName,
				"VM(this).cmd({'type':'ajax','src':'editor/editNode?nodeId=NEW&nodeType="+subAdaptor+"&nodeParent="+viewNode.getNodeId()+"&parentType="+viewNode.getNodeType()+"&viewId="+viewNode.getViewId()+"&nodeMode="+nodeMode+"&fromModule="+DemoConstants.MOD_EXPERIENCE+"'});").setDisabled(singleLimit));
			}
		}
	}

	public static DfishViewNode getRootViewNode(String viewId) {
		DfishViewNode node = new DfishViewNode();
		node.setViewId(viewId);
		node.setNodeId(DemoConstants.ID_ROOT);
		return node;
	}
	
	public static View buildSelTargetView(String nodeId,List<DfishViewNode> nodeList,String viewId) {
		View view=new View();
		//FIXME 应该试用模板
		VerticalLayout root=new VerticalLayout("root");
		root.setStyle("border:1px solid #999;background-color:#FFF;");
		root.setHmin(1);
		root.setWmin(1);
		view.setNode(root);
//		root.add(new Html("","编辑组件信息")
//			.setStyle("background-color:#EEE;line-height:30px;padding-left:6px;font-size:16px"),
//			"38");
		TreePanel tree=new TreePanel("f_tree");
		root.add(tree,"*");
		tree.setStyle("background-color:white");
		tree.setScroll(true).setScrollClass(TreePanel.SCROLL_MINI);
//		form.setScroll(true);
		
		HorizontalLayout bbp=new HorizontalLayout("b_btn")
			.setStyle("background-color:#EEE; text-align:right;");
		root.add(bbp,"0");
		
//		bbp.setAlign(HorizontalLayout.ALIGN_RIGHT);//FIXME
		Leaf compRoot=new Leaf();
		tree.add(compRoot.setId(DemoConstants.ID_ROOT).setText("[根目录]")
				.setOn(Leaf.EVENT_CLICK, "$.alert('该目录不可选');VM(this).data('admit','false');").setStyle("color:#a39896;"));
		//FIXME tree.addNode
//		tree.setPub(new Leaf().setOn("click", "VM(this).data('pNode',this.x.id);"));
		
		doMoveToNodeId(compRoot,nodeList,nodeId);
		
		ButtonBar btnBar = new ButtonBar("btnBar");
		root.add(btnBar, "50");
		btnBar.setAlign(ButtonBar.ALIGN_RIGHT);
		btnBar.setCls("dlg-foot").setSpace(8);
		
		btnBar.add(new Button("","确定","var admit = VM(this).data('admit');if(admit=='true'){VM(this).cmd('moveNode');}").setCls("btn btn-submit"));
		btnBar.add(new Button("","取消","$.dialog(this).close();").setCls("btn"));
		view.addCommand("moveNode",new JSCommand("var vm=VM(this);" +
				"vm.cmd({'type':'ajax','src':'editor/moveNode?nodeId="+nodeId+"&viewId="+viewId+"&pNode='+vm.data('pNode')});"));
		return view;
	}
	
	public static void doMoveToNodeId(Leaf compRoot ,List<DfishViewNode> nodeList,String nodeId){
		HashSet<String> allId=new HashSet<String>();
		HashMap<String,List<DfishViewNode>> allSubs=new HashMap<String,List<DfishViewNode>>();
		HashSet<String> mark = new HashSet<String>();
		mark.add(nodeId);
		
		String nodeIdsType = "";
		String nodeIdParent="";
		
		for(DfishViewNode node:nodeList){
			allId.add(node.getNodeId());
			List<DfishViewNode> subs=allSubs.get(node.getNodeParent());
			if(subs==null){
				subs =new ArrayList<DfishViewNode>(); 
				allSubs.put(node.getNodeParent(),subs);
			}
			if(node.getNodeId().equals(nodeId)){
				nodeIdsType=node.getNodeType();
				nodeIdParent=node.getNodeParent();
			}
			subs.add(node);
		}
		mark = cantMoveToChildNodeId(nodeId,nodeList,mark);
		mark.add(nodeIdParent);

		for(DfishViewNode node:nodeList){
			if(!mark.contains(node.getNodeId())){
				if(cantMoveToLimitNodeId(node,allSubs,mark,nodeIdsType)){
					mark.add(node.getNodeId());
				}
			}
		}
		
		for(DfishViewNode node:nodeList){
			if(allId.contains(node.getNodeParent())){
				continue;
			}
			fillMoveTreeItem(compRoot,node,allSubs,mark);
		}
	}
	

	public static View editCreatorPanel(DfishView dview){
		View view =new View();
		VerticalLayout hl = new VerticalLayout("root");
		hl.setCls("bd-gray");
		hl.setStyle("background:#FFF;");
		view.add(hl);
		
		FormPanel fp = new FormPanel("form");
		fp.addHidden("viewId", dview.getViewId());
		fp.addHidden("viewCreator", dview.getViewCreator());
		
		fp.add(new Text("viewName", "名称", dview.getViewName()).setReadonly(true));
//		fp.add(new Text("viewCreator", "创建人", dview.getViewCreator()));
		fp.add(new Textarea("viewRemark", "备注", dview.getViewRemark()));
		fp.add(new Spinner("viewOrder", "排序", dview.getViewOrder(), 10, 99999999, 10).setReadonly(true));
	
		fp.add(new Label("创建时间", DateUtil.format(dview.getCreateTime())));
		fp.add(new Label("最后更新", DateUtil.format(dview.getUpdateTime())));
		hl.add(fp,"*");
		
		ButtonBar bb2=new ButtonBar("btn");
		bb2.setAlign(ButtonBar.ALIGN_RIGHT)
		.setCls("dlg-foot").setSpace(8).setStyle("padding-right:20px")
		.setWmin(20).setHmin(1);
		
		String saveCmd = "var str = '';" +
				"if(!VM(this).f('viewRemark').val()) {str += '确定备注不填写？';} " +
				"if(str == ''){this.cmd('saveView');}" +
				"else if(confirm(str)) {this.cmd('saveView');}";
		bb2.add(new SubmitButton("确定").setOn(SubmitButton.EVENT_CLICK, saveCmd).setCls("btn btn-submit"));
		
		
		bb2.add(new Button("取消").setOn(Button.EVENT_CLICK, "$.close(this);").setCls("btn"));
		hl.add(bb2,"50");
		
		view.addCommand("saveView", new SubmitCommand("editor/saveVersion").setRange("form"));
		return view;
	}

	public static HashSet<String> cantMoveToChildNodeId(String nodeId ,List<DfishViewNode> nodeList,HashSet<String> mark) {
		if(!mark.contains(nodeId)){
			mark.add(nodeId);
		}
		boolean isDo = false;
		for(DfishViewNode node:nodeList){
			if(!mark.contains(node.getNodeId())){
				if(mark.contains(node.getNodeParent())){
					mark.add(node.getNodeId());
					isDo = true;
				}
			}
		}
		if(isDo){
			mark=cantMoveToChildNodeId(nodeId,nodeList,mark);
		}
		return mark;
	}
	
	private static boolean cantMoveToLimitNodeId(DfishViewNode node,HashMap<String,List<DfishViewNode>> allSubs,HashSet<String> mark ,String nodeIdsType){
		
			ComponentInfo cinfo=AdaptorManager.getInstance().getCompInfo(); 
			ComponentRelation crel=AdaptorManager.getInstance().getCompRelation();
			String type=node==null?null:node.getNodeType();
			List<ComponentRelation.Information> acceptTypes=crel.getAcceptType(type);
			
			LinkedHashMap<String,List<ComponentRelation.Information>> cates=new LinkedHashMap<String,List<ComponentRelation.Information>>();
			if(acceptTypes!=null){
				for(ComponentRelation.Information acceptType:acceptTypes){
					String cate=cinfo.getCategory(acceptType.getSubType());
					List<ComponentRelation.Information> typesInCate=cates.get(cate); 
					if(typesInCate==null){
						typesInCate=new ArrayList<ComponentRelation.Information>();
						cates.put(cate,typesInCate);
					}
					typesInCate.add(acceptType);
				}
			}
			List<String> cateKeys=new ArrayList<String>(cates.keySet());
			cinfo.sortCategory(cateKeys);
			
			boolean containSingle=false;
			
			HashSet<String> subTypes=new HashSet<String>();
			List<DfishViewNode> subs=allSubs.get(node.getNodeId());
			HashSet<String> subViewNodeIds=new HashSet<String>();
			if(subs!=null){
				for(DfishViewNode sub:subs){
					subTypes.add(sub.getNodeType());
					ComponentData cd=AdaptorManager.parseData(sub);
					if(cd!=null&&cd.getProps()!=null){
						subViewNodeIds.add(cd.getProps().get("id"));
					}
				}
			}
			for(String subType:subTypes){
				if(crel.acceptSingle(type , subType)||
						((type==null||type.equals(null)&&"View".equals(subType)))){
					containSingle=true;
					break;
				}
			}
			for(String cate:cateKeys){
				for(ComponentRelation.Information subAdaptor:cates.get(cate)){
					boolean singleLimit=containSingle&&(subAdaptor.isSingle()||((type==null||type.equals(null)&&"View".equals(subAdaptor))));
					if((!singleLimit)&&subAdaptor.equals(nodeIdsType)){
						return false;
					}
				}
			}
			
			boolean newBtnDisabled=acceptTypes==null||acceptTypes.size()==0;
			
			Map<String,List<ComponentRelation.Information>> specialPart=crel.getSpecialParts(type);
			if(Utils.notEmpty(specialPart)){
				
				for(Map.Entry<String,List<ComponentRelation.Information>> entry:specialPart.entrySet()){
					boolean singleLimit= subViewNodeIds.contains("<"+entry.getKey()+">");
					for(ComponentRelation.Information subAdaptor:entry.getValue()){
						if(subAdaptor.getSubType().equals(nodeIdsType)){
							return false;
						}
					}
				}
			}
		return true;
	}
	
	private static void fillMoveTreeItem(Leaf shell, DfishViewNode node,
			HashMap<String, List<DfishViewNode>> allSubs ,HashSet<String> mark) {
		if(node==null){return;}
		shell.setOpen(true);
		
		if(Utils.isEmpty(node.getNodeParent())||node.getNodeParent().equals(DemoConstants.ID_ROOT)){
			shell.setSrc("editor/open/ROOT"+node.getViewId());
		}else{
			shell.setSrc("editor/open/"+node.getNodeParent());
		}
		
		Leaf t=new Leaf().setId(node.getNodeId());
		shell.add(t);
		if(mark.contains(node.getNodeId())) {
			t.setOn(Leaf.EVENT_CLICK, "$.alert('该目录不可选！！');VM(this).data('admit','false');");
			t.setStyle("color:#a39896;");
		} else {
			t.setOn(Leaf.EVENT_CLICK, "VM(this).data('admit','true');VM(this).data('pNode',this.x.id);");
		}
		if(Utils.notEmpty(node.getNodeName())){
			if(node.getNodeName().length()<10){
				t.setText(node.getNodeType()+"("+node.getNodeName()+")");
			} else {
				t.setText(node.getNodeType()+"("+node.getNodeName().substring(0, 8)+"...)");
			}

		}else{
			t.setText(node.getNodeType());
		}
		List<DfishViewNode> subs=allSubs.get(node.getNodeId());
		if(subs!=null){
			for(DfishViewNode sub:subs){
				fillMoveTreeItem(t,sub,allSubs,mark);
			}
		}
	}
	
	public static View buildToImportView(String viewId) {
		View view = PubView.buildDialogView();
		
		FormPanel form = (FormPanel) view.findNodeById(PubView.DIALOG_MAIN);
		
		form.add(new DefaultUploadFile("uploadFile", "附件").setRequired(true).setFile_upload_limit(1).setFile_types("*.zip"));
		
		ButtonBar btnBar = (ButtonBar) view.findNodeById(PubView.DIALOG_BTN);
		btnBar.add(0, new SubmitButton("确定").setOn(SubmitButton.EVENT_CLICK, "this.cmd('import');"));
		
		view.addCommand("import",new SubmitCommand( "editor/importView?viewId=" + viewId).setRange(PubView.DIALOG_MAIN));
		
		return view;
	}

}
